package cn.mysdp.biz.domain;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import org.springframework.beans.BeanUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Criterion {
    private String condition;

    private Object value;

    private Object secondValue;

    private boolean noValue;

    private boolean singleValue;

    private boolean betweenValue;

    private boolean listValue;

    private String typeHandler;

    public String getCondition() {
        return condition;
    }

    public Object getValue() {
        return value;
    }

    public Object getSecondValue() {
        return secondValue;
    }

    public boolean isNoValue() {
        return noValue;
    }

    public boolean isSingleValue() {
        return singleValue;
    }

    public boolean isBetweenValue() {
        return betweenValue;
    }

    public boolean isListValue() {
        return listValue;
    }

    public String getTypeHandler() {
        return typeHandler;
    }

    public Criterion(String condition) {
        super();
        this.condition = condition;
        this.typeHandler = null;
        this.noValue = true;
    }

    public Criterion(String condition, Object value, String typeHandler) {
        super();
        this.condition = condition;
        this.value = value;
        this.typeHandler = typeHandler;
        if (value instanceof List<?>) {
            this.listValue = true;
        } else {
            this.singleValue = true;
        }
    }

    public Criterion(String condition, Object value) {
        this(condition, value, null);
    }

    public Criterion(String condition, Object value, Object secondValue, String typeHandler) {
        super();
        this.condition = condition;
        this.value = value;
        this.secondValue = secondValue;
        this.typeHandler = typeHandler;
        this.betweenValue = true;
    }

    public Criterion(String condition, Object value, Object secondValue) {
        this(condition, value, secondValue, null);
    }

    public static String getAjaxString(String inputString) {
        String str = getCamelCaseString(inputString, false);
        StringBuilder sb = new StringBuilder();

        boolean nextUpperCase = false;
        for (int i = 0; i < inputString.length(); i++) {
            char c = inputString.charAt(i);
            if (Character.isUpperCase(c)) {
                if (i > 0) {
                    sb.append("_");
                }
                sb.append(Character.toLowerCase(c));
            } else {
                sb.append(c);
            }
        }
        return sb.toString();

    }
    public static String getCamelCaseString(String inputString,
                                            boolean firstCharacterUppercase) {
        StringBuilder sb = new StringBuilder();

        boolean nextUpperCase = false;
        for (int i = 0; i < inputString.length(); i++) {
            char c = inputString.charAt(i);

            switch (c) {
                case '_':
                case '-':
                case '@':
                case '$':
                case '#':
                case ' ':
                case '/':
                case '&':
                    if (sb.length() > 0) {
                        nextUpperCase = true;
                    }
                    break;

                default:
                    if (nextUpperCase) {
                        sb.append(Character.toUpperCase(c));
                        nextUpperCase = false;
                    } else {
                        sb.append(Character.toLowerCase(c));
                    }
                    break;
            }
        }

        if (sb.length() > 0) {
            if (firstCharacterUppercase) {
                sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
            } else {
                sb.setCharAt(0, Character.toLowerCase(sb.charAt(0)));
            }
        }

        return sb.toString();
    }

    public static List<Object> toList(JSONArray array, Class clz) throws IllegalAccessException, InstantiationException {
        if (array == null || array.size() == 0) {
            return new ArrayList<>();
        }
        Map<String, Field> clzFieldMap = new HashMap<>();
        Class superClz = clz;
        while(superClz != null) {
            Field[] fields = superClz.getDeclaredFields();
            for(Field field : fields) {
                String fieldName;
                if (field.isAnnotationPresent(JSONField.class)) {
                    JSONField jsonField = field.getAnnotation(JSONField.class);
                    fieldName = jsonField.name();
                } else {
                    fieldName = getAjaxString(field.getName());
                }
                clzFieldMap.put(fieldName, field);
            }
            superClz = superClz.getSuperclass();
        }
        List<Object> ret = new ArrayList<>();
        for(int i = 0; i < array.size(); i++) {
            Object o = array.get(i);
            Object newO = null;
            try {
                newO = clz.newInstance();
            } catch (Exception e) {
                throw e;
            }
            if (o instanceof JSONObject) {
                for (String p : ((JSONObject) o).keySet()) {
                    if (clzFieldMap.containsKey(p)) {
                        Object v = ((JSONObject) o).get(p);
                        if (v instanceof String) {
                            clzFieldMap.get(p).setAccessible(true);
                            clzFieldMap.get(p).set(newO, v);
                        }
                    }
                }
            } else if (o instanceof Map) {
                Map map = (Map) o;
                for(Object key: map.keySet()) {
                    if (clzFieldMap.containsKey(key)) {
                        Object v = map.get(key);
                        if (v instanceof String) {
                            clzFieldMap.get(key).setAccessible(true);
                            clzFieldMap.get(key).set(newO, v);
                        }
                    }
                }
            } else {
                BeanUtils.copyProperties(o, newO);
            }
            ret.add(newO);
        }
        return ret;
    }
}
